package net.vkits.anjiamiao.domain.service;

import net.vkits.anjiamiao.domain.event.VerifyCodeEvent;
import net.vkits.anjiamiao.domain.model.Customer;
import net.vkits.anjiamiao.domain.model.VerifyCode;
import net.vkits.anjiamiao.domain.repository.CustomerRepository;
import net.vkits.anjiamiao.domain.repository.VerifyCodeRepository;
import net.vkits.common.exceptions.DuplicatePhoneExeption;
import net.vkits.common.exceptions.NoSuchVerifyCode;
import net.vkits.common.exceptions.TooManyTimesException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

/**
 * Created by ethan-liu on 16/6/5.
 */
@Service
public class VerifyCodeService {

    private static final Logger logger = LoggerFactory.getLogger(VerifyCodeService.class);

    @Value("${myconfig.GETSMSCODE_TIMES: 20}")
    private int GETSMSCODE_TIMES;
    @Value("${myconfig.VALID_TIME: 10}")
    private int VALID_TIME;

    @Resource
    private VerifyCodeRepository verifyCodeRepository;
    @Resource
    private CustomerRepository customerRepository;
    @Resource
    private ApplicationContext applicationContext;

    public void create(String cellPhoneNum, String verifyCode) {
        List<VerifyCode> verifyCodes = verifyCodeRepository.findByCellPhoneNumAndSendDate(cellPhoneNum, LocalDate.now());
        if (verifyCodes.size() < GETSMSCODE_TIMES) {
            verifyCodeRepository.save(new VerifyCode(cellPhoneNum, verifyCode, VALID_TIME));
            applicationContext.publishEvent(new VerifyCodeEvent(cellPhoneNum, verifyCode));
        } else {
            // 抛出自定义异常提示获取次数超过限制
            throw new TooManyTimesException();
        }
    }

    public boolean validateOrCreate(String cellPhoneNum, String verifyCode) {
        Optional<VerifyCode> verifyCodeOptional = verifyCodeRepository.findByCellPhoneNumAndVerifyCodeAndUsedFalse(cellPhoneNum, verifyCode);
        if (verifyCodeOptional.isPresent()) {
            VerifyCode code = verifyCodeOptional.get();
            code.use();
            verifyCodeRepository.save(code);
            if (code.isExpired()) {
                logger.info("VerifyCode is expired: {}", code);
                throw new NoSuchVerifyCode();
            } else {
                Optional<Customer> customerOptional = customerRepository.findByCellPhoneNumAndDeletedFalse(cellPhoneNum);
                Customer customer = customerOptional.orElse(Customer.createCustomer(cellPhoneNum));
                customerRepository.save(customer);
                return true;
            }
        }
        return false;
    }

    public boolean validateAndChangePhone(String cellPhone, String newPhone, String verifyCode) {
        Optional<VerifyCode> verifyCodeOptional = verifyCodeRepository.findByCellPhoneNumAndVerifyCodeAndUsedFalse(cellPhone, verifyCode);
        if (verifyCodeOptional.isPresent()) {
            VerifyCode code = verifyCodeOptional.get();
            code.use();
            verifyCodeRepository.save(code);
            if (code.isExpired()) {
                logger.info("VerifyCode is expired: {}", code);
                throw new NoSuchVerifyCode();
            } else {
                Optional<Customer> byCellPhoneNum = customerRepository.findByCellPhoneNumAndDeletedFalse(newPhone);
                if (byCellPhoneNum.isPresent()) {
                    logger.info("already has the phone in system. cannot change it.");
                    throw new DuplicatePhoneExeption();
                }
                Optional<Customer> customerOptional = customerRepository.findByCellPhoneNumAndDeletedFalse(cellPhone);
                customerOptional.ifPresent(customer -> {
                    customer.changeCellPhoneNum(newPhone);
                    customerRepository.save(customer);
                });
                return true;
            }
        }
        throw new NoSuchVerifyCode();
    }
}